using DG.Tweening;
using DG.Tweening.Core;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Serialization;

namespace WorkFlow.TweenGo
{
    public enum TweenStart
    {
        None,
        OnEnable,
        OnAwake,
        OnStart
    }

    public interface ITweenGoControl
    {
        public TweenStart StartTime { get; }
        public void Play();
        public void Clear();
    }
    
    public abstract class TweenGoBase<TTarget,TValue> : MonoBehaviour, ITweenGoControl where TTarget : Component where TValue : struct
    {
        [Header("Tween对象")]
        [SerializeField] private bool initValueOnAwake;
        [Header("Tween对象")]
        [SerializeField] private bool initValueOnEnable;
        [Header("循环")]
        [SerializeField] private bool loop;
        [Header("是否不使用TimeScale")]
        [SerializeField] private bool notTimeScale;
        [Header("Tween对象")]
        [SerializeField] private TTarget target;
        [Header("开始时机")]
        [SerializeField] private TweenStart tweenStart;
        [Header("缓动曲线")]
        [SerializeField] private Ease ease;
        [Header("持续时间")]
        [SerializeField] private float duration = 0.35f;
        [Header("运行延迟")]
        [SerializeField] private float delay;
        [Header("是否使用当前值当作开始值")]
        [SerializeField] private bool useCurrentValueToStart;
        [Header("开始值")][HideIf("useCurrentValueToStart")]
        [SerializeField] private TValue startValue;
        [Header("结束值")]
        [SerializeField] private TValue endValue;
        
        [SerializeField] UnityEvent onStartEvent = new UnityEvent();
        [FormerlySerializedAs("onCompleteVent")] [SerializeField] UnityEvent onCompleteEvent = new UnityEvent();
        [SerializeField] UnityEvent<TValue> onUpdateEvent = new UnityEvent<TValue>();
        
        public UnityEvent OnStartEvent => onStartEvent;
        public UnityEvent OnCompleteEvent => onCompleteEvent;
        public UnityEvent<TValue> OnUpdateEvent => onUpdateEvent;
        
        public TweenStart StartTime => tweenStart;

        public TTarget Target
        {
            get => target;
            set => target = value;
        }
        public bool NotUseTimeScale
        {
            get => notTimeScale;
            set => notTimeScale = value;
        }
        public bool Loop
        {
            get => loop;
            set => loop = value;
        }
        public float Delay
        {
            get => delay;
            set => delay = value;
        }

        public float Duration
        {
            get => duration;
            set => duration = value;
        }

        public Ease TweenEase
        {
            get => ease;
            set => ease = value;
        }
        public TValue StartValue
        {
            get => startValue;
            set => startValue = value;
        }
        public TValue EndValue
        {
            get => endValue;
            set => endValue = value;
        }

        Tweener _tweener;
        
        public bool IsPlaying => _tweener != null && _tweener.IsPlaying();

        protected virtual void Awake()
        {
            if (target == null)
                target = (TTarget)GetComponent(typeof(TTarget));
            if (initValueOnAwake && enabled)
            {
                SetInitializeValue();
            }
            if(tweenStart == TweenStart.OnAwake)
                StartTween();
        }
        
        protected virtual void OnEnable()
        {
            if (initValueOnEnable)
            {
                SetInitializeValue();
            }
            if(tweenStart == TweenStart.OnEnable)
                StartTween();
        }
        protected virtual void Start()
        {
            if(tweenStart == TweenStart.OnStart)
                StartTween();
        }

        protected virtual void OnDisable()
        {
            _tweener?.Pause();
        }

        [Button]
        private void StartTween()
        {
            _tweener?.Pause();
            if (target != null)
            {
                if (_tweener == null)
                {
                    _tweener = CreateTween(GetStartValue,UpdateValue,endValue,duration).SetEase(ease).SetDelay(delay).SetUpdate(notTimeScale);
                    _tweener.OnComplete(OnComplete);
                    onStartEvent?.Invoke();
                    _tweener.Play();
                }
                else
                {
                    onStartEvent?.Invoke();
                    _tweener.Restart();
                }
            }
        }

        
        protected virtual void OnComplete()
        {
            if (loop)
            {
                StartTween();
            }
            else
            {
                OnCompleteEvent?.Invoke();
                _tweener = null;
            }
        }
        
        public void Clear()
        {
            if (_tweener != null)
            {
                _tweener.Kill();
                _tweener = null;
            }
        }

        public void SetInitializeValue()
        {
            SetValue(startValue);
        }

        public void Play()
        {
            if(tweenStart == TweenStart.None || _tweener == null)
                StartTween();
            else
            {
                _tweener.Restart();
            }
        }

        /// <summary>
        /// 需要子类覆盖 默认返回Inspector的开始值
        /// </summary>
        /// <returns></returns>
        protected virtual TValue CurrentValue()
        {
            return startValue;
        } 
        
        private TValue GetStartValue()
        {
            if (useCurrentValueToStart)
            {
                return CurrentValue();
            }
            return startValue;
        }

        public void ApplyStartValue()
        {
            SetValue(GetStartValue());
        }
        
        protected abstract Tweener CreateTween(DOGetter<TValue> startValueGetter, DOSetter<TValue> setter,
            TValue endValue,
            float duration);

        private void UpdateValue(TValue value)
        {
            SetValue(value);
            OnUpdateEvent?.Invoke(value);
        }
        
        protected abstract void SetValue(TValue value);

        [Button]
        private void KillTween()
        {
            if(_tweener != null)
                _tweener.Kill();
            _tweener = null;
        }
        [Button("置换 开始/结束值")]
        private void ReversalValue()
        {
            (startValue, endValue) = (endValue, startValue);
        }

        private void OnDestroy()
        {
            KillTween();
        }
    }
}
